[% setvar title Arrays: Notation for declaring and creating arrays %]
<div id="archive-notice">
    <h3>This file is part of the Perl 6 Archive</h3>
    <p>To see what is currently happening visit <a href="http://www.perl6.org/">http://www.perl6.org/</a></p>
</div>
<div class='pod'>
<a name='TITLE'></a><h1>TITLE</h1>
<p>Arrays: Notation for declaring and creating arrays</p>
<a name='VERSION'></a><h1>VERSION</h1>
<pre>  Maintainer: Jeremy Howard &lt;<a href='mailto:j@howard.fm'>j@howard.fm</a>&gt;
  Date: 8 Sep 2000
  Last Modified: 21 Sep 2000
  Mailing List: <a href='mailto:perl6-language-data@perl.org'>perl6-language-data@perl.org</a>
  Number: 203
  Version: 2
  Status: Frozen</pre>
<a name='DISCUSSION'></a><h1>DISCUSSION</h1>
<p>No objections were noted to the proposals in this RFC. A change of name
from :bounds to :shape was accepted.</p>
<a name='ABSTRACT'></a><h1>ABSTRACT</h1>
<p>RFC 202 described the need to be able to declare a data structure that
contains elements of the same type stored contiguously in memory, which is
called an <i>array</i>. This RFC outlines the syntax to declare and create
arrays. The syntax to create arrays is identical to that to create lists
of lists (described in <i><a href='http://search.cpan.org/perldoc?perllol'>perllol</a></i> in the Perl 5 documentation). The syntax
to declare the type of elements is the standard type syntax.</p>
<p>RFC 203 describes a syntax for multidimensional indexing of arrays. A
syntax to declare the bounds of the dimensions is described in this RFC
using a new ':shape' attribute.</p>
<a name='DESCRIPTION'></a><h1>DESCRIPTION</h1>
<a name='Compact arrays'></a><h2>Compact arrays</h2>
<p>It is proposed that if a list is declared that specifies a simple type for
its elements:</p>
<pre>  my int @a;
  </pre>
<p>then that list be stored as an array--that is, contiguously in memory.
These arrays support <i>all</i> the same syntax as lists. Therefore any
description of syntax for a 'list' also applies to an 'array', and visa
versa. However, their implementation is very different.</p>
<a name=':shape attribute'></a><h2>:shape attribute</h2>
<p>Furthermore, it is proposed that lists accept a new <code>:shape</code> attribute:</p>
<pre>  my @a :shape(3);</pre>
<p>that defines the number of elements in a list.</p>
<p>This is equivalent to:</p>
<pre>  my @a;
  $#a = 3-1;
  </pre>
<p>except that an attempt at accessing beyond $a[3] would result in an error
if :shape(3) is set. Specfically, adding a :shape attribute to a
declaration has two effects on the array:</p>
<ul>
<li><a name='1'></a>1</li>
<p>Adds range checking (since exceptions are defined for access outside
the range)</p>
<li><a name='2'></a>2</li>
<p>Allows the block of memory to be preallocated</p>
</ul>
<p>(2) can also be achieved by simply setting the bottom right element to
undef, or by setting @#array. The behaviour of (1) removes
autovivification of new elements, since an exception is raised
instead.</p>
<p>:shape doesn't actually reshape. If the returned array overshoots
specified bounds of :shape, an exception is raised. Reshaping is done
with reshape() (RFC 148), merge()/demerge() (RFC 90), and
part()/flatten() (RFC 91).</p>
<p>The :shape attribute can also accept a list:</p>
<pre>  my @b :shape(3,3);</pre>
<p>The second element of the list is the number of elements in the list, as
before. The first element is the number of lists that are referenced as
elements of the list. Therefore</p>
<pre>  my @b :shape(3,3);
  $b[3][4] = 0;   # Error: access beyond bounds of @b</pre>
<p>would result in an error. :shape can take as many arguments as
required--an n-element list declares a list with at most n levels of
nesting, with the maximum index at level x being (n-x). Because lists of
lists support multidimensional indexing (see RFC 204) the :shape attribute
effectively specifies the bounds of a multidimensional structure.</p>
<p>The parameters of :shape are optional if an array is assigned in the
declaration. Therefore:</p>
<pre>  my int @array :shape = @rvalue;</pre>
<p>is equivalent to:</p>
<pre>  my int @array :shape(@#rvalue) = @rvalue;</pre>
<p>The bounds of an array or list can be specified at run time, of course:</p>
<pre>  my @t1 :shape(@dimList) = getFromSomeplace();</pre>
<a name='Combining compact storage and :shape attribute'></a><h2>Combining compact storage and :shape attribute</h2>
<p>Efficient multidimensional arrays can be declared by combining a fixed
simple type with the :shape attribute:</p>
<pre>  my int @b :shape(4,4);</pre>
<p>Perl in this case would set aside enough room for sixteen ints, and store
an attribute with @b that it had two dimensions, each indexed by (0..3).
Because @b here is stored as an array, and supports multidimensional
indexing (see RFC 204), it is a true multidimensional array.</p>
<p>Although @b looks just like a normal list of lists that happens to
have a type and an attribute, it is implemented as a multidimensional
array. Therefore</p>
<pre>  my int @b :shape(4,4);
  @b = ([1,2,3,4],
        [5,6,7,8],
        [9,10,11,12],
        [13,14,15,16]);</pre>
<p>creates a multidimensional array @b that contains all sixteen ints in a
contiguous block of memory, but can be accessed using standard list of
lists syntax, along with the extensions proposed in RFC 204.</p>
<p>Where the type and bounds of an array can be derived at run time, it is
not necessary to specify them explicitly:</p>
<pre>  my int @t1 :shape(@dimList) = getFromSomeplace();
  my int @t2 :shape(@dimList) = getFromSomeplaceElse();
  my @prod = @t1 * @t2;   # @prod magically has type (int) and :shape (@dimlist)</pre>
<p>Note that this is using an element-wise multiplication operation,
described in RFC 82. If either @t1 or @t2 was unbounded (i.e. had no
:shape attribute) then @prod would also be unbounded.</p>
<p>A list (of lists...) that contains elements of the same type can be
converted to an array by specifying its type:</p>
<pre>  my @some_LOL = ([1,2],
                  [3,4]);
  my int @array = @some_LOL;
  </pre>
<p>and its bounds can be locked in as well if required:</p>
<pre>  my @some_LOL = ([1,2],
                  [3,4]);
  my int @array :shape(@#some_LOL) = @some_LOL;</pre>
<a name='IMPLEMENTATION'></a><h1>IMPLEMENTATION</h1>
<p>Too early to get into much detail beyond the obvious... Clearly arrays are
not a list of SVs, but are the raw data stored contiguously in memory,
along with the attributes of the array stored someplace.</p>
<p>:shape applies to lists as well, of course (because lists and arrays share
identical syntax), but this should be fine because it is just an
attribute.</p>
<p>Arrays do not require :shape to be specified. If not specified, they
should grow by doubling in size (like lists), but programmers will be
encouraged to avoid this because a new contiguous memory block will have
to be found each time. Programmers may also allocate memory after the fact
with '@#' (see RFC 206).</p>
<a name='REFERENCES'></a><h1>REFERENCES</h1>
<p>RFC 202: Overview of multidimensional array RFCs</p>
<p>perllol in the Perl 5 documentation</p>
<p>Implementation in PDL: <a href='http://pdl.sourceforge.net/PDLdocs/Internals.html' target='_blank'>pdl.sourceforge.net</a></p>
</div>
